#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <limits.h>

typedef int Graph;
typedef int ElementType;
typedef struct MINHEAP MinHeap;
typedef struct STACK Stack;
typedef struct HEAPELEMENT HeapElement;
struct MINHEAP {
	HeapElement *elm;
	int size;
	int capacity;
};
struct STACK{
	ElementType elm;
	Stack *next;
};
struct HEAPELEMENT{
	int index;
	int dis;
};
MinHeap *HeapInit(int);
_Bool HeapEmpty(MinHeap *);
_Bool HeapFull(MinHeap*);
void InsertHeap(MinHeap*,HeapElement);
HeapElement DeleteHeap(MinHeap*);
Stack *StackInit(void);
_Bool StackEmpty(Stack*);
void Push(Stack*,ElementType);
ElementType Pop(Stack*);
int Dijkstra(int n,Graph (*dis)[n],Graph (*price)[n],int start,int end,int *s);

MinHeap* HeapInit(int capacity){
	MinHeap *ret=malloc(sizeof(MinHeap));
	ret->elm=malloc(sizeof(HeapElement)*(capacity+1));
	ret->elm[0].dis=INT_MIN;
	ret->size=0;
	ret->capacity=capacity;
	return ret;
}
_Bool HeapEmpty(MinHeap *h){
	if( h->size == 0 )
		return true;
	return false;
}
_Bool HeapFull(MinHeap *h){
	if( h->size == h->capacity )
		return true;
	return false;
}
void InsertHeap(MinHeap *h,HeapElement e){
	if( HeapFull(h) ){
		printf("Heap Full\n");
		return;
	}
	int i=++h->size;
	while( h->elm[i/2].dis > e.dis ){
		h->elm[i]=h->elm[i/2];
		i=i/2;
	}
	h->elm[i]=e;
	return;
}
HeapElement DeleteHeap(MinHeap *h){
	int i=1;
	HeapElement ret=h->elm[1];
	HeapElement e=h->elm[h->size--];
	while( 2*i <= h->size ){
		if( 2*i < h->size && h->elm[2*i].dis>h->elm[2*i+1].dis && e.dis > h->elm[2*i+1].dis ){
			h->elm[i]=h->elm[2*i+1];
			i=2*i+1;
		}else if( h->elm[2*i].dis < e.dis ){
			h->elm[i]=h->elm[2*i];
			i=2*i;
		}else{
			break;
		}
	}
	h->elm[i]=e;
	return ret;
}
Stack *StackInit(void){
	Stack *s=malloc(sizeof(Stack));
	s->next=NULL;
	return s;
}
_Bool StackEmpty(Stack *s){
	if(s->next)
		return false;
	return true;
}
void Push(Stack *s,ElementType e){
	Stack *new=malloc(sizeof(Stack));
	new->elm=e;
	new->next=s->next;
	s->next=new;
	return;
}
ElementType Pop(Stack *s){
	ElementType ret=s->next->elm;
	Stack *tmp=s->next;
	s->next=s->next->next;
	free(tmp);
	return ret;
}

#define MAX_CITY 250000

int main(void){
	int n,m,s,d;
	scanf("%d %d %d %d",&n,&m,&s,&d);
	int dis[n][n],price[n][n];
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			price[i][j]=-1;
			dis[i][j]=-1;
		}
	}
	int c1,c2,ds,pe;
	for(int i=0;i<m;i++){
		scanf("%d %d %d %d",&c1,&c2,&ds,&pe);
		dis[c1][c2]=dis[c2][c1]=ds;
		price[c1][c2]=price[c2][c1]=pe;
	}
	int distance;
	int a=Dijkstra(n,dis,price,s,d,&distance);
	printf("%d %d",a,distance);
	return 0;
}


int Dijkstra(int n,Graph (*dis)[n],Graph (*price)[n],int start,int end,int *s){
	int p[n],d[n],path[n];
	_Bool collect[n];
	for(int i=0;i<n;i++){
		path[i]=-1;
		p[i]=-1;
		d[i]=INT_MAX;
		collect[i]=false;
	}
	MinHeap *h=HeapInit(MAX_CITY);
	d[start]=0;
	p[start]=0;
	InsertHeap(h,(HeapElement){.index=start,.dis=d[start]});
	HeapElement e;
	while( !HeapEmpty(h) ){
		e=DeleteHeap(h);
		collect[e.index]=true;
		for(int i=0;i<n;i++){
			if( dis[e.index][i]!=-1 && !collect[i] && d[i]>d[e.index]+dis[e.index][i] ){
				d[i]=d[e.index]+dis[e.index][i];
				p[i]=p[e.index]+price[e.index][i];
				path[i]=e.index;
				InsertHeap(h,(HeapElement){.index=i,.dis=d[i]});
			}else if ( dis[e.index][i]!=-1 && !collect[i] && (d[i]==d[e.index]+dis[e.index][i]) ){
				if( p[i] > p[e.index]+price[e.index][i] ){
					p[i]=p[e.index]+price[e.index][i];
					path[i]=e.index;
					//InsertHeap(h,(HeapElement){.index=i,.dis=d[i]});
				}
			}else{

			}
/*
			if( dis[e.index][i]!=-1 && !collect[i] && d[i]>=d[e.index]+dis[e.index][i] ){
				if( d[i] == d[e.index]+dis[e.index][i] ){
					if( p[i] > p[e.index]+price[e.index][i] ){
						p[i]=p[e.index]+price[e.index][i];
						path[i]=e.index;
						//InsertHeap(h,(HeapElement){.index=i,.dis=d[i]});
					}
				}else{
					d[i]=d[e.index]+dis[e.index][i];
					p[i]=p[e.index]+price[e.index][i];
					path[i]=e.index;
					InsertHeap(h,(HeapElement){.index=i,.dis=d[i]});
				}
			}
*/
		}
	}
	*s=p[end];
	return d[end];
}
